package model

import (
	"errors"
	"fmt"
	"ordersystem/config"
	"ordersystem/database"
	"sync"
	"time"
)

type Order struct {
	Id          int32     `json:"id" xml:"id" form:"id" gorm:"primaryKey"`
	LabId       int32     `json:"lab_id" xml:"lab_id" form:"lab_id"`
	UserId      int32     `json:"user_id" xml:"user_id" form:"user_id"`
	State       int8      `json:"state" xml:"state" form:"state"`
	Start       time.Time `json:"start" xml:"start" form:"start"`
	End         time.Time `json:"end" xml:"end" form:"end"`
	Description string    `json:"description" xml:"description" form:"description"`
	Reason      string    `json:"reason" xml:"reason" form:"reason"`
	CreateAt    time.Time `json:"create_at" xml:"create_at" form:"create_at" gorm:"autoCreateTime"`
	UpdateAt    time.Time `json:"update_at" xml:"update_at" form:"update_at" gorm:"autoUpdateTime"`
}

func (o *Order) QueryOrder() (map[string]interface{}, error) {
	conn := database.GetMysqlConnection()
	var result map[string]interface{}
	conn.Model(&Order{}).Joins("left join users on users.id = orders.user_id").Joins("left join labs on labs.id = orders.lab_id").Select("orders.*,labs.*,users.name").Where("orders.id = ?", o.Id).First(&result)
	return result, nil
}

func QueryOrderNumber(userId int32, isAdmin bool) int64 {
	conn := database.GetMysqlConnection()
	var result int64
	if userId == 0 {
		conn.Table("orders").Count(&result)
		return result
	} else {
		if isAdmin {
			conn.Table("orders").Joins("left join labs on labs.id = orders.lab_id").Where("labs.creator = ?", userId).Count(&result)
			return result
		} else {
			conn.Table("orders").Where("user_id=?", userId).Count(&result)
			return result
		}
	}
}

func QueryOrders(userId int32, isAdmin bool, page int) ([]map[string]interface{}, error) {
	conn := database.GetMysqlConnection()
	var result []map[string]interface{}
	if userId == 0 {
		conn.Table(config.TABLE_ORDERS).Joins("left join users on users.id = orders.user_id").Joins("left join labs on labs.id = orders.lab_id").Select("labs.*,orders.*,users.name").Order("orders.id desc").Limit(config.PAGE_SIZE).Offset(page * config.PAGE_SIZE).Scan(&result)
	} else if userId != 0 {
		if isAdmin {
			conn.Table(config.TABLE_ORDERS).Joins("left join labs  on labs.id = orders.lab_id").Joins("left join users on users.id = orders.user_id").Where("labs.creator = ?", userId).Select("labs.*,orders.*,users.name").Order("orders.id desc").Limit(config.PAGE_SIZE).Offset(page * config.PAGE_SIZE).Scan(&result)
		} else {
			conn.Table(config.TABLE_ORDERS).Joins("left join labs on labs.id = orders.lab_id").Joins("left join users on users.id = orders.user_id").Where("orders.user_id = ?", userId).Select("labs.*,orders.*,users.name").Order("orders.id desc").Limit(config.PAGE_SIZE).Offset(page * config.PAGE_SIZE).Scan(&result)
		}
	}
	return result, nil
}

var lock sync.Mutex

func (order *Order) CreateOrder() error {
	conn := database.GetMysqlConnection()
	fmt.Println(order)
	order.Start = order.Start.Local()
	order.End = order.End.Local()

	if order.Start.Hour() < 8 || order.Start.Hour() > 21 {
		return errors.New(config.REQUEST_ORDER_TIME_INCORRECT)
	}

	if order.Start.Unix() > order.End.Unix() {
		return errors.New(config.REQUEST_ORDER_TIME_INCORRECT)
	}

	lock.Lock()

	defer func() {
		lock.Unlock()
	}()

	var isExist int64

	conn.Table(config.TABLE_ORDERS).Where("( start <= ? and end >= ? ) or (start <= ? and end >= ?) or (start <= ? and  end >= ?)", order.Start, order.Start, order.End, order.End, order.Start, order.End).Select("id").Limit(1).Count(&isExist)

	if isExist >= int64(1) {
		return errors.New(config.REQUEST_TIME_HAVE_BEEN_ORDER)
	}

	order.State = 0

	conn.Model(order).Create(order).Commit()

	return nil
}

func (order *Order) UpdateOrderToActive() error {
	conn := database.GetMysqlConnection()

	conn.Model(order).First(order)
	fmt.Println(order)
	lock.Lock()

	defer func() {
		lock.Unlock()
	}()

	var isExist int64

	conn.Model(&Order{}).Where("( start < ? and end > ? ) or (start < ? and end > ?) or (start > ? and  end < ?)", order.Start, order.Start, order.End, order.End, order.Start, order.End).Select("id").Limit(1).Count(&isExist)

	if isExist >= int64(1) {
		return errors.New(config.REQUEST_TIME_HAVE_BEEN_ORDER)
	}

	order.State = 0
	order.Reason = ""

	conn.Model(order).Save(order).Commit()

	return nil

}

func (order *Order) UpdateOrder() error {
	conn := database.GetMysqlConnection()
	fmt.Println(order)
	conn.Model(order).Updates(map[string]interface{}{"state": 1, "reason": order.Reason}).Commit()
	return nil
}

func (order *Order) DeleteOrder() error {
	conn := database.GetMysqlConnection()

	if conn.Model(order).Delete(order).Commit().RowsAffected == 0 {
		return errors.New(config.RESPONSE_DATABASE_OPERATION_ERROR)
	}
	return nil
}

func DeleteOrderByYear(year int32) error {
	conn := database.GetMysqlConnection()
	conn.Table(config.TABLE_ORDERS).Where("year(start) = ?", year).Delete(&Order{})
	return nil
}
